home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Microsoft Multimedia Viewer How-To CD
/
Microsoft Multimedia Viewer How-To CD.iso
/
mvsample
/
progsamp
/
eplist
/
eplist.c
next >
Wrap
C/C++ Source or Header
|
1993-03-21
|
25KB
|
907 lines
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <stdlib.h>
#include <viewer.h>
#include "EPLIST.h"
#include "scrolwin.h"
#include "mvbtask.h"
#include "graphics.h"
#include "parse.h"
#define BORDER_WIDTH 8
#define BEVEL_WIDTH 3
HANDLE ghModule; // Our Module handle
char szEPClassName[] = "ListPane";
char szScrollClassName[] = "EPScrollWin";
/************************************************************************
* ShowMessage
*
* Load a string resource and display in a message box.
*
************************************************************************/
void ShowMessage(
HWND hWnd, // Parent window for message box
int nMessage, // String resource ID for message
int nIcon) // Type of icon to display
{
char szMessage[512];
MessageBeep(nIcon);
if(LoadString(ghModule, nMessage, szMessage, 511) > 0)
{
MessageBox(hWnd, szMessage, szEPClassName,
MB_OK | nIcon);
}
else
{
MessageBox(hWnd, "Unspecified error.", szEPClassName,
MB_OK | nIcon);
}
}
/************************************************************************
* LibMain
*
* Initialization function for the DLL
*
* - Registers the two window classes used for the embedded pane
* - Initializes the task table
*
* Returns: TRUE if initialization succeeds, FALSE otherwise
*
************************************************************************/
BOOL CALLBACK LibMain(HANDLE hModule, int cbHeap, LPSTR lpchCmdLine)
{
WNDCLASS wc;
ghModule = hModule;
wc.lpszClassName = szEPClassName;
wc.style = CS_GLOBALCLASS;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.lpszMenuName = NULL;
wc.hbrBackground = COLOR_WINDOW + 1;
wc.hInstance = hModule;
wc.lpfnWndProc = PaneListProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(LPLISTINFO);
if(!RegisterClass(&wc))
return FALSE;
wc.style = CS_DBLCLKS;
wc.lpszClassName = szScrollClassName;
wc.lpfnWndProc = ScrollWinProc;
if(!RegisterClass(&wc))
return FALSE;
InitTasks();
return TRUE;
}
/************************************************************************
* AddLI
*
* Adds a list info structure to the task list table
*
* Returns: Index of the list entry if successful, -1 otherwise.
*
************************************************************************/
int AddLI(
LPVWRINFO lpVwrInfo, // Task info for current instance
LPLISTINFO lpLI) // To add to list
{
int i;
for(i = 0; i < MAX_WINDOWS && lpVwrInfo->alpLI[i]; i++);
if(i != MAX_WINDOWS)
{
lpVwrInfo->alpLI[i] = lpLI;
return i;
}
return -1;
}
/************************************************************************
* RemoveLI
*
* Deletes a list info structure from the task list table
*
************************************************************************/
void RemoveLI(
LPVWRINFO lpVwrInfo, // Task info for current instance
LPLISTINFO lpLI) // To remove from list
{
int i;
for(i = 0; i < MAX_WINDOWS && lpVwrInfo->alpLI[i] != lpLI; i++);
if(i != MAX_WINDOWS)
{
lpVwrInfo->alpLI[i] = NULL;
}
}
/************************************************************************
* FreeLI
*
* Frees memory used by a list info structure
*
************************************************************************/
void FreeLI(
LPLISTINFO lpLI) // To remove from list
{
if(lpLI->lpszText)
GlobalFreePtr(lpLI->lpszText);
if(lpLI->hwndScroll)
DestroyWindow(lpLI->hwndScroll);
if(lpLI->hfontLB)
DeleteObject(lpLI->hfontLB);
GlobalFreePtr(lpLI);
}
/************************************************************************
* FindLI
*
* Finds a previously stored list info structure
*
* Returns: Handle to list info structure with matching author-data
* string. Returns NULL if no such list exists.
*
************************************************************************/
LPLISTINFO FindLI(
LPVWRINFO lpVwrInfo, // Task info for current instance
LPSTR lpszAuthor) // Author data string to find
{
int i;
for(i = 0; i < MAX_WINDOWS; i++)
{
if(!lpVwrInfo->alpLI[i])
continue;
if(lstrcmp(lpszAuthor, lpVwrInfo->alpLI[i]->szAuthorData) == 0)
return lpVwrInfo->alpLI[i];
}
return NULL;
}
/*************************************************************************
* DoCommand
*
* This function submits the selected command to Viewer. To determine
* which command is selected, it looks at the list info structure passed
* to lpLI.
*
* Returns: Zero if successful; otherwise, returns an error code.
*
*************************************************************************/
int DoCommand(
LPVWRINFO lpVwrInfo, // Viewer instance info (VWR handle)
LPSTR lpszCommand) // List info structure
{
VWR vwrRet;
if(lpVwrInfo == NULL)
return LISTERR_NOVWRINFO;
if(lpszCommand == NULL)
return 0;
vwrRet = VwrCommand(lpVwrInfo->vwr, NULL, lpszCommand, cmdoptNONE);
if(vwrRet == lpVwrInfo->vwr)
return 0;
else
return LISTERR_NOVWR;
}
/*************************************************************************
* GetPaneSize
*
* This function is called in response to the EWM_QUERYSIZE message.
* It fills the POINT structure pointed to by lpptSize with the x and y
* extents of the pane. The uses the authored size values for a display
* pane, but for a printed pane, it must scale the size values to
* match the resolution of the printer.
*
* Returns: TRUE if successful, FALSE otherwise. This return value can
* be passed to the EWM_QUERYSIZE return; TRUE means use the
* size values pointed to by lpptSize, and FALSE means ignore
* the size values.
*
*************************************************************************/
BOOL GetPaneSize(
LPLISTINFO lpLI, // List info structure
HDC hdc, // HDC for display device
LPPOINT lpptSize) // Receives pane dimensions
{
POINT ptDisp, ptPrt;
HDC hdcDisplay;
if(lpLI == NULL)
return FALSE;
lpptSize->x = lpLI->iWidth;
lpptSize->y = lpLI->iHeight;
// If this is a printer DC, scale the pane appropriately.
if(GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASPRINTER)
{
hdcDisplay = CreateIC("DISPLAY", NULL, NULL, NULL);
ptDisp.x = GetDeviceCaps(hdcDisplay, LOGPIXELSX);
ptDisp.y = GetDeviceCaps(hdcDisplay, LOGPIXELSY);
DeleteDC(hdcDisplay);
ptPrt.x = GetDeviceCaps(hdc, LOGPIXELSX);
ptPrt.y = GetDeviceCaps(hdc, LOGPIXELSY);
lpptSize->x = lpptSize->x * (ptPrt.x / ptDisp.x);
lpptSize->y = lpptSize->y * (ptPrt.y / ptDisp.y);
}
return TRUE;
}
/**************************************************************************
*
* PrintPane
*
* This function is called in response to the EWM_PRINT message. The
* function creates a print image of the pane and draws the image to
* the device and into the rectangle identified by the lpRI parameter.
*
*************************************************************************/
void PrintPane(
LPLISTINFO lpLI, // List info structure
LPRENDERINFO lpRI) // Identifies print device & print location
{
RECT rc;
HFONT hfont, hfontOld;
int nBevel, nBorder;
if(lpLI == NULL)
return;
// Need to make a new font for the printer device.
hfont = MakeFont(lpRI->hds, lpLI->szFont, lpLI->iFontSize);
if(hfont)
{
hfontOld = SelectObject(lpRI->hds, hfont);
}
// Scale the pane border so it's proportional
nBevel = BEVEL_WIDTH*(lpRI->rc.right-lpRI->rc.left)/lpLI->iWidth;
RectBorder(lpRI->hds, &lpRI->rc, nBevel);
CopyRect(&rc, &lpRI->rc);
nBorder = BORDER_WIDTH*(lpRI->rc.right-lpRI->rc.left)/lpLI->iWidth;
rc.left += nBorder;
rc.top += nBorder;
rc.right -= nBorder;
rc.bottom -= nBorder;
Rectangle(lpRI->hds, rc.left, rc.top, rc.right, rc.bottom);
rc.left += 1;
rc.top += 1;
rc.right -= 1;
rc.bottom -= 1;
DrawList(lpRI->hds, rc.left, rc.top, &rc, lpLI->alpszText,
lpLI->nTop, lpLI->nCurSel, lpLI->nItems);
if(hfont)
{
SelectObject(lpRI->hds, hfontOld);
DeleteObject(hfont);
}
}
/*************************************************************************
* PaneListProc
*
* This is the window procedure for the embedded pane. It processes
* messages for the pane.
*
*************************************************************************/
LONG CALLBACK PaneListProc(
HWND hwnd, // Window handle of pane
UINT msg, // Message to process
WPARAM wParam, // Message parameter
LPARAM lParam) // Message parameter
{
LPLISTINFO lpLI;
LPVWRINFO lpVwrInfo;
int iRet;
switch(msg)
{
case WM_CREATE:
{
// The pane can be created when the topic is first displayed,
// when the pane is scrolled into view, or when the topic is
// printed or copied. Viewer passes an EWDATA structure with
// the WM_CREATE message; this structure identifies the title
// and Viewer version and specifies whether the pane is being
// created for display (default), printing, or copying.
LPCREATESTRUCT lpCreate = (LPCREATESTRUCT)lParam;
LPEWDATA lpew = (LPEWDATA)lpCreate->lpCreateParams;
if(lpew == NULL)
return -1;
if(lpew->idMajVersion == 0 && lpew->idMinVersion == 0)
return -1;
lpVwrInfo = GetTaskData(GetWindowWord(hwnd, GWW_HINSTANCE));
if(lpVwrInfo == NULL)
{
ShowMessage(NULL, LISTERR_NOVWRINFO, MB_ICONEXCLAMATION);
return -1;
}
if(lpVwrInfo->szMVB[0] == '\0')
CopyFilename(lpVwrInfo->szMVB, lpew->szFileName);
// If the pane is being created for copying or printing, first
// try to find the matching display version so we can use its
// list-info structure. This lets us create a print or copy
// image that matches the state of the displayed pane
// NOTE: the display version might not exist if the pane was
// scrolled off-screen.
lpLI = NULL;
if(lpew->dwFlags & EWF_PRINT || lpew->dwFlags & EWF_COPY)
{
lpLI = FindLI(lpVwrInfo, lpew->szAuthorData);
}
if(lpLI == NULL)
{
iRet = InitPane(hwnd, lpew, &lpLI, lpCreate->cx, lpCreate->cy);
if(iRet)
{
return -1;
}
else
{
if(AddLI(lpVwrInfo, lpLI) == -1)
{
FreeLI(lpLI);
ShowMessage(NULL, LISTERR_TOOMANY, MB_ICONEXCLAMATION);
return -1;
}
}
}
// Store the list info with the window
SetWindowLong(hwnd, 0, (LONG)lpLI);
return 0;
}
case WM_SHOWWINDOW:
// When Viewer makes our pane visible, we can show the scrolling
// window.
lpLI = (LPLISTINFO)GetWindowLong(hwnd, 0);
if(lpLI)
{
if(hwnd == lpLI->hwndPane && lpLI->hwndScroll)
ShowWindow(lpLI->hwndScroll, SW_SHOWNA);
}
break;
case WM_DESTROY:
// We can destroy the list information when the pane is destroyed.
// However, since print/copy panes can share data with the
// displayed panes, we must first check to make sure the current
// window handle (hwnd) matches the one recorded in the pane data
// structure (lpLI->hwndPane).
lpLI = (LPLISTINFO)GetWindowLong(hwnd, 0);
if(lpLI && lpLI->hwndPane == hwnd)
{
lpVwrInfo = GetTaskData(GetWindowWord(hwnd, GWW_HINSTANCE));
if(lpVwrInfo)
RemoveLI(lpVwrInfo, lpLI);
else
ShowMessage(NULL, LISTERR_NOVWRINFO, MB_ICONEXCLAMATION);
FreeLI(lpLI);
}
break;
case WM_PAINT:
{
// This window is only responsible for painting the beveled
// border.
PAINTSTRUCT ps;
RECT rc;
BeginPaint( hwnd, &ps );
GetClientRect(hwnd, &rc);
RectBorder(ps.hdc, &rc, BEVEL_WIDTH);
EndPaint( hwnd, &ps );
return 0L;
}
case WM_USER_LISTDBLCLK:
// This message is posted from the scrolling window when the
// user double-clicks a list entry.
lpVwrInfo = GetTaskData(GetWindowWord(hwnd, GWW_HINSTANCE));
iRet = DoCommand(lpVwrInfo, (LPSTR)lParam);
if(iRet)
ShowMessage(GetParent(hwnd), iRet, MB_ICONEXCLAMATION);
return 0;
case WM_USER_LISTSELECT:
// By responding to this message rather than the above message,
// the pane could submit commands whenever the selection changed.
return 0;
case EWM_RENDER:
// This message is only received if our EWM_COPY code fails.
return NULL;
case EWM_COPY:
{
// When the topic is copied, just provide the currently selected
// line in the list box. Printing the entire list box would look
// strange in the copy text.
LPSTR lpszCopy;
HANDLE hCopy;
lpLI = (LPLISTINFO)GetWindowLong(hwnd, 0);
if(lpLI == NULL)
return NULL;
lpszCopy = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
lstrlen(lpLI->alpszText[lpLI->nCurSel])+1);
if(lpszCopy)
{
lstrcpy(lpszCopy, lpLI->alpszText[lpLI->nCurSel]);
hCopy = GlobalPtrHandle(lpszCopy);
GlobalUnlock(hCopy);
return hCopy;
}
else
return NULL;
}
case EWM_PRINT:
// Print the pane using the device context supplied with the
// RENDERINFO structure.
lpLI = (LPLISTINFO)GetWindowLong(hwnd, 0);
PrintPane(lpLI, (LPRENDERINFO)lParam);
return TRUE;
case EWM_QUERYSIZE:
// Provide size values for the pane
lpLI = (LPLISTINFO)GetWindowLong(hwnd, 0);
return GetPaneSize(lpLI, (HDC)wParam, (LPPOINT)lParam);
case EWM_ASKPALETTE:
return NULL;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
/*************************************************************************
* ReadBaggageFile
*
* This function reads the contents of a baggage file into the lpszText
* buffer. The function just returns the file size if the lpszText
* parameter is NULL.
*
* Returns: count of bytes in file (if lpszText == NULL)
* count of bytes read if successful
* -1 if an error occurs
*
*************************************************************************/
long ReadBaggageFile(
LPSTR lpszMVB, // Specifies the MVB filename
LPSTR lpszBagFile, // Specifies the baggage filename
LPSTR lpszText, // To receive baggage file text
long lcbMax) // Max number of characters to copy
{
char szPath[_MAX_PATH];
HMMIO hFile = NULL;
long lcBytes = -1;
// Construct a baggage filename and try to open the file.
wsprintf(szPath, "%s+%s", lpszMVB, lpszBagFile);
hFile = mmioOpen(szPath, NULL, MMIO_READ);
if(hFile == NULL)
{
return -1;
}
// Get file size and return if lpszText is NULL
lcBytes = mmioSeek(hFile, 0, SEEK_END);
if(lpszText == NULL)
{
mmioClose(hFile, 0);
return lcBytes;
}
// Read the file contents and close the file
mmioSeek(hFile, 0, SEEK_SET);
if(lcbMax > lcBytes)
lcBytes = mmioRead(hFile, lpszText, lcBytes);
else
lcBytes = mmioRead(hFile, lpszText, lcbMax-1);
mmioClose(hFile, 0);
*(lpszText + lcBytes) = 0;
return lcBytes;
}
/*************************************************************************
* ReadCmdList
*
* This function reads the list file from baggage and parses the file
* contents into a series of list entries and associated commands.
* The function initializes the alpszCommand and alpszText arrays with
* the starting locations of the list entries. It inserts NULL characters
* into the buffer to terminate the list entries and commands.
*
*************************************************************************/
int ReadCmdList(
LPSTR lpszMVB, // Name of MVB file
LPLISTINFO lpLI) // List information structure
{
LPSTR lpszTab, lpszText;
int i;
long lcBaggage;
// First get the count of bytes in the baggage file
lcBaggage = ReadBaggageFile(lpszMVB, lpLI->szListFilename, NULL, 0);
if(lcBaggage == -1)
return LISTERR_BAGGAGE;
// Allocate a buffer and read the contents into memory
lpLI->lpszText = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT,
lcBaggage +1);
if(lpLI->lpszText == NULL)
return LISTERR_MEMORY;
if(ReadBaggageFile(lpszMVB, lpLI->szListFilename, lpLI->lpszText,
lcBaggage+1) == -1)
{
GlobalFreePtr(lpLI->lpszText);
lpLI->lpszText = NULL;
return LISTERR_BAGGAGE;
}
// Build the topic list.
for(i = 0, lpszText = lpLI->lpszText;
*lpszText && i < MAX_LIST;
lpszText++)
{
lpLI->alpszText[i] = lpszText;
for(lpszTab = NULL; *lpszText && *lpszText != '\r'; lpszText++)
{
if(*lpszText == '\t')
lpszTab = lpszText;
}
if(lpszTab == NULL)
{
lpLI->alpszCommand[i] = NULL;
}
else
{
*lpszTab = 0;
lpLI->alpszCommand[i] = lpszTab+1;
}
if(*lpszText == '\r')
*lpszText++ = 0;
i++;
}
lpLI->nItems = i;
return 0;
}
/**************************************************************************
*
* InitPaneAspect
*
* This function initializes the visual aspects of the pane (size, font,
* etc.) using the author data in the LISTINFO structure.
*
* Returns: Zero if successful; otherwise, returns an error code.
*
**************************************************************************/
int InitPaneAspect(
HWND hwnd, // Window handle of embedded pane
LPLISTINFO lpLI, // Info block for embedded pane
int cx, // Default size for pane
int cy)
{
HDC hdc;
TEXTMETRIC tm;
HFONT hfontOld;
int cxScreen, cyScreen;
long lx, ly;
// Create a font and get the text metrics.
if(*lpLI->szFont == '\0')
lstrcpy(lpLI->szFont, "Helv");
if(lpLI->iFontSize == 0)
lpLI->iFontSize = 8;
hdc = GetDC(hwnd);
if(hdc == NULL)
return LISTERR_CREATEFAILED;
lpLI->hfontLB = MakeFont(hdc, lpLI->szFont, lpLI->iFontSize);
if(lpLI->hfontLB)
hfontOld = SelectObject(hdc, lpLI->hfontLB);
GetTextMetrics(hdc, &tm);
if(hfontOld)
SelectObject(hdc, hfontOld);
ReleaseDC(hwnd, hdc);
lpLI->iLineSpace = tm.tmHeight + tm.tmExternalLeading;
// Set measurements of embedded pane. If author specified values,
// convert them from text measurements to pixel measurements.
hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
cxScreen = GetDeviceCaps(hdc, HORZRES);
cyScreen = GetDeviceCaps(hdc, VERTRES);
DeleteDC(hdc);
if(lpLI->iWidth == 0)
{
lpLI->iWidth = cx;
}
else
{
lx = (long)lpLI->iWidth * (long)cxScreen / (long)1024;
lpLI->iWidth = (UINT)lx;
}
if(lpLI->iHeight == 0)
{
lpLI->iHeight = cy;
}
else
{
ly = (long)lpLI->iHeight * (long)cyScreen / (long)1024;
lpLI->iHeight = (UINT)ly;
}
lpLI->iLines = (lpLI->iHeight-BORDER_WIDTH*2) / lpLI->iLineSpace;
lpLI->iHeight = lpLI->iLines * lpLI->iLineSpace + BORDER_WIDTH * 2;
// Set current selection & position values
lpLI->nTop = lpLI->nCurSel = 0;
return 0;
}
/*************************************************************************
* InitPane : This BIG function initializes all the information for the
* embedded pane. It parses the author-data string and sets
* appropriate values in the pane information structure. It also
* creates the child window that displays the list and handles
* scrolling logic.
*
* Returns: Zero on success or -1 on failure (passed to WM_CREATE return).
*
*************************************************************************/
int InitPane(
HWND hwnd, // Handle of new embedded pane window
LPEWDATA lpew, // Embedded pane create info
LPLISTINFO FAR *lplpLI, // To receive pointer to list info structure
int cx, // Default sizes from LPCREATE
int cy)
{
LPLISTINFO lpLI; // Pane information structure
int iRet = 0;
*lplpLI = NULL;
// Allocate pane information structure
lpLI = (LPLISTINFO)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(LISTINFO));
if(lpLI == NULL)
{
iRet = LISTERR_MEMORY;
goto ReturnError;
}
// Parse the author data string, read the list information from
// baggage, and initialize the display data for the pane.
iRet = ParseAuthorString(lpLI, lpew->szAuthorData);
if(iRet)
goto ReturnError;
iRet = ReadCmdList(lpew->szFileName, lpLI);
if(iRet)
goto ReturnError;
iRet = InitPaneAspect(hwnd, lpLI, cx, cy);
if(iRet)
goto ReturnError;
// If this is a display pane, create a child window to handle the
// scrolling interface. This window is not needed for panes created
// just for printing or copying.
if(!(lpew->dwFlags & EWF_PRINT || lpew->dwFlags & EWF_COPY))
{
lpLI->hwndScroll = CreateWindow(szScrollClassName, NULL,
WS_CHILD | WS_BORDER,
BORDER_WIDTH,
BORDER_WIDTH,
lpLI->iWidth -BORDER_WIDTH*2,
lpLI->iHeight-BORDER_WIDTH*2,
hwnd, NULL, ghModule, lpLI);
}
lpLI->hwndPane = hwnd;
*lplpLI = lpLI;
return 0;
ReturnError:
if(lpLI) GlobalFreePtr(lpLI);
return iRet;
}
/**************************************************************************
* LDLLHandler: Processes notification messages sent from Viewer to the
* DLL. This one only processes initialization and termination
* messages.
*
**************************************************************************/
LONG CALLBACK LDLLHandler(
UINT msg, // Message to process
LPARAM lParam1, // Message parameter
LPARAM lParam2) // Message parameter
{
LPVWRINFO lpVwrInfo;
switch(msg)
{
case DW_WHATMSG:
return DC_INITTERM;
case DW_INIT:
lpVwrInfo = AddTask(LOWORD(lParam1));
if(lpVwrInfo == NULL)
return FALSE;
lpVwrInfo->vwr = VwrFromHinst(LOWORD(lParam1));
return TRUE;
case DW_TERM:
DeleteTask(LOWORD(lParam1));
return TRUE;
}
}